Análisis Técnico
El proyecto propuesto tiene como objetivo utilizar análisis técnico y herramientas financieras para generar oportunidades de trading en un par de divisas durante un período de entrenamiento y prueba. Se espera que el proyecto tenga la estructura básica de proyectos de Python y que se divida en tareas predefinidas para cada perfil. Además, se deben definir los cuatro criterios del sistema de trading y se debe realizar una optimización y backtest financiero del sistema utilizando parámetros específicos. El proyecto también incluirá aspectos estadísticos y computacionales, como la propuesta de estudios técnicos, la definición de una función de utilidad y parámetros a optimizar, el espacio de búsqueda y el método de optimización utilizado. Finalmente, se debe aplicar el sistema de trading a los datos de prueba y presentar los resultados a través de gráficas y tablas.
Utilizar entre 2 y 4 estudios técnicos como herramientas para la generación de oportunidades de trading, lo que equivale a utilizar análisis técnico.
import functions
import data
import visualizations
import plotly.io as pio
# Train
train_df = data.data_open_2("AUDUSD_train.csv")
train_df
| timeStamp | Open | High | Low | Close | Mid | |
|---|---|---|---|---|---|---|
| 0 | 2020-01-01 | 0.701508 | 0.704500 | 0.701508 | 0.701700 | 0.701700 |
| 1 | 2020-01-02 | 0.701892 | 0.702100 | 0.698130 | 0.701951 | 0.701951 |
| 2 | 2020-01-03 | 0.698370 | 0.698661 | 0.693140 | 0.698519 | 0.698519 |
| 3 | 2020-01-06 | 0.694729 | 0.695900 | 0.692602 | 0.694420 | 0.694420 |
| 4 | 2020-01-07 | 0.693720 | 0.694100 | 0.686111 | 0.693731 | 0.693731 |
| ... | ... | ... | ... | ... | ... | ... |
| 258 | 2020-12-28 | 0.761348 | 0.762400 | 0.755960 | 0.761191 | 0.761191 |
| 259 | 2020-12-29 | 0.758858 | 0.762500 | 0.758478 | 0.758892 | 0.758892 |
| 260 | 2020-12-30 | 0.761200 | 0.768622 | 0.760720 | 0.760990 | 0.760990 |
| 261 | 2020-12-31 | 0.768900 | 0.774140 | 0.768690 | 0.768929 | 0.768929 |
| 262 | 2021-01-01 | 0.777180 | 0.820760 | 0.769823 | 0.770297 | 0.770297 |
263 rows × 6 columns
# Test
test_df = data.data_open_2("AUDUSD_test.csv")
test_df
| timeStamp | Open | High | Low | Close | Mid | |
|---|---|---|---|---|---|---|
| 0 | 2021-02-01 | 0.762062 | 0.766401 | 0.76135 | 0.761998 | 0.761998 |
| 1 | 2021-02-02 | 0.763330 | 0.766190 | 0.75667 | 0.763460 | 0.763460 |
| 2 | 2021-02-03 | 0.760900 | 0.762700 | 0.76024 | 0.760821 | 0.760821 |
| 3 | 2021-02-04 | 0.763633 | 0.764750 | 0.75900 | 0.763600 | 0.763600 |
| 4 | 2021-02-05 | 0.760092 | 0.766000 | 0.75844 | 0.760300 | 0.760300 |
| ... | ... | ... | ... | ... | ... | ... |
| 257 | 2022-01-26 | 0.715880 | 0.717800 | 0.71508 | 0.715880 | 0.715880 |
| 258 | 2022-01-27 | 0.712140 | 0.712140 | 0.70421 | 0.712300 | 0.712300 |
| 259 | 2022-01-28 | 0.703700 | 0.704722 | 0.69686 | 0.703550 | 0.703550 |
| 260 | 2022-01-31 | 0.699428 | 0.707914 | 0.69932 | 0.699800 | 0.699800 |
| 261 | 2022-02-01 | 0.706590 | 0.711794 | 0.70347 | 0.706830 | 0.706830 |
262 rows × 6 columns
# Train
train_df["timeStamp"].min(),train_df["timeStamp"].max()
('2020-01-01', '2021-01-01')
# Test
test_df["timeStamp"].min(),test_df["timeStamp"].max()
('2021-02-01', '2022-02-01')
El Exponential Moving Average (EMA) es un indicador técnico utilizado en análisis técnico de valores bursátiles para suavizar los datos de precios y mostrar la tendencia subyacente del precio de un activo. A diferencia del Simple Moving Average (SMA), el EMA da más peso a los precios más recientes, lo que lo convierte en un indicador más sensible a los cambios de precio más recientes.
La fórmula para el EMA es la siguiente:
$$ EMA(i) = (Precio(i) - EMA(i-1)) * (2 / (n + 1)) + EMA(i-1)$$Donde:
El valor de n en la fórmula del EMA es el número de períodos utilizados para calcular el EMA. Por ejemplo, si n es igual a 10, entonces el EMA se calcula utilizando los precios de cierre de los últimos 10 períodos. El valor de n puede ser ajustado por el analista técnico en función de sus preferencias y objetivos de análisis.
El Parabolic SAR (Stop and Reverse) es un indicador técnico utilizado en análisis técnico de valores bursátiles para determinar el momento y la dirección del precio de un activo. La función del Parabolic SAR es identificar la tendencia del precio y proporcionar señales para comprar o vender el activo.
El SAR fue desarrollado por el analista técnico J. Welles Wilder y fue presentado en su libro "New Concepts in Technical Trading Systems" en 1978. Es una herramienta comúnmente utilizada por los traders y analistas técnicos para ayudar en la toma de decisiones de inversión. La fórmula para el valor del Parabolic SAR se calcula de acuerdo con la siguiente fórmula:
Si la tendencia es alcista: $$SAR(i) = SAR(i - 1) + AF(i - 1) * (EP(i - 1) - SAR(i - 1))$$ Si la tendencia es bajista: $$SAR(i) = SAR(i - 1) - AF(i - 1) * (SAR(i - 1) - EP(i - 1))$$
Donde:
El valor inicial del Parabolic SAR se establece como el mínimo entre los precios mínimos de las dos primeras filas. Es decir:
$$SAR(1) = \min(Low(1), Low(2))$$Donde Low(1) es el precio mínimo para la primera fila, y Low(2) es el precio mínimo para la segunda fila.
El Aroon Oscillator es un indicador técnico utilizado en análisis técnico de valores bursátiles para medir la fuerza de la tendencia y la probabilidad de que se produzca un cambio en la tendencia. Es una versión del indicador Aroon que se representa como un oscilador con valores que oscilan alrededor de una línea central de cero. El Aroon Oscillator puede tomar valores positivos o negativos. Los valores positivos indican que la tendencia alcista está ganando fuerza, mientras que los valores negativos indican que la tendencia bajista está ganando fuerza. Un valor de cero indica que no hay tendencia clara en el mercado.
La línea central de cero del Aroon Oscillator se utiliza como una señal para la toma de decisiones de inversión. Cuando el Aroon Oscillator cruza por encima de cero, se considera una señal de compra, y cuando cruza por debajo de cero, se considera una señal de venta.
Su fórmula es: $$Aroon Oscillator = Aroon Up - Aroon Down$$ Donde: $$Aroon Up = ((N - Periodo desde el último máximo) / N) * 100$$ $$Aroon Down = ((N - Periodo desde el último mínimo) / N) * 100$$ Donde:
El Aroon Up y el Aroon Down son indicadores separados que miden la cantidad de períodos desde el último máximo más alto y el último mínimo más bajo, respectivamente. Ambos indicadores varían entre 0 y 100, donde 100 indica que el máximo o el mínimo más reciente se alcanzó en el período actual, y 0 indica que no se alcanzó ningún máximo o mínimo en el período considerado.
El Aroon se utiliza comúnmente en análisis técnico para identificar la fuerza y la dirección de la tendencia en el mercado y para determinar cuándo se pueden producir cambios en la tendencia.
La estrategia de trading utiliza los indicadores Parabolic SAR, Aroon Oscillator y EMA para tomar decisiones de compra y venta. Las reglas de entrada son las siguientes:
Si el precio de cierre es menor que la EMA, el indicador Parabolic SAR está por encima del precio y el Aroon Oscillator es negativo, se cierra la posición larga abierta previamente (venta). Las reglas de Stop Loss y Take Profit son las siguientes:
Si el capital diario alcanza un valor que representa una ganancia igual o superior al valor de take_profit_ratio del capital inicial, se activa la orden de Take Profit para cerrar la posición larga abierta.
Si el capital diario alcanza un valor que representa una pérdida igual o superior al valor de stop_loss_ratio del capital inicial, se activa la orden de Stop Loss para cerrar la posición larga abierta. La fórmula para entrar en una posición larga es la siguiente: $$Long_Entry = (Close > EMA) \& (ParabolicSAR < Close) \& (AroonOscillator > 0) \& (Position == 0)$$ La fórmula para salir de una posición larga es la siguiente: $$Exit = (Close < EMA) \& (ParabolicSAR > Close) \& (AroonOscillator < 0) \& (Position == 1)$$ Donde:
Close es el precio de cierre del activo.
Se busca maximizar el retorno total de la estrategia de trading, variando el Take Profit, Stop Loss y tamaño de la operación
Esto significa que hay 10,181,391 posibles combinaciones de los valores de estos tres parámetros en el espacio de búsqueda.
Asignando 0.5 segundos de tiempo transcurrido para cada vez que corres el código con una configuración de parámetros, dadas 10,181,391 posibles combinaciones, el tiempo es de:
Tiempo de búsqueda exhaustiva = 5,090,695.5 segundos
El tiempo de búsqueda exhaustiva para el óptimo de los 10,181,391 combinaciones posibles sería aproximadamente 59 días.
El método 'L-BFGS-B' es un algoritmo de optimización que pertenece a la familia de métodos cuasi-Newtonianos. 'L-BFGS-B' es la versión limitada del algoritmo 'BFGS' (Broyden-Fletcher-Goldfarb-Shanno) que admite restricciones de límites en los parámetros de optimización.
El algoritmo 'BFGS' es un método iterativo que utiliza una aproximación de la matriz de Hesse inversa para calcular la dirección de búsqueda. La versión 'L-BFGS' (Limited-memory BFGS) es una variante que utiliza una cantidad limitada de memoria, lo que la hace más adecuada para problemas de optimización con un gran número de variables.
El algoritmo 'L-BFGS-B' combina las ventajas del algoritmo 'L-BFGS' con la capacidad de manejar restricciones de límites en los parámetros de optimización. Esto es útil en situaciones donde se necesita restringir los valores de los parámetros a un rango específico.
# Preprocesamiento de dataframes para evaluación de estrategia
# Creación de indicadores
# Exponential Moving Average y Aroon Oscillator
train_df = (
train_df.pipe(functions.calculate_ema, 20)
.pipe(functions.calculate_aroon_oscillator)
)
# Parabolic SAR
train_df["Parabolic_SAR"] = functions.calculate_parabolic_sar(train_df)
# Exponential Moving Average y Aroon Oscillator
test_df = (
test_df.pipe(functions.calculate_ema, 20)
.pipe(functions.calculate_aroon_oscillator)
)
# Parabolic SAR
test_df["Parabolic_SAR"] = functions.calculate_parabolic_sar(test_df)
# Optimización de parámetros y Backtesting (sólo sobre Train se realiza)
best_params_train,iter_val_test = functions.best_fit_params(train_df)
print("Best take_profit_ratio:", best_params_train[0])
print("Best stop_loss_ratio:", best_params_train[1])
print("Best position_size:", best_params_train[2])
# Creación del portafolio a partir de la estrategia con parámetros optimizados
# Backtesting sobre entrenamiento
portfolio = functions.run_trading_strategy(train_df,
capital=100000,
take_profit_ratio=best_params_train[0],
stop_loss_ratio=best_params_train[1],
position_size=best_params_train[2])
# Sobre datos de prueba
portfolio_test = functions.run_trading_strategy(test_df,
capital=100000,
take_profit_ratio=best_params_train[0],
stop_loss_ratio=best_params_train[1],
position_size=best_params_train[2])
# Métricas de atribución al desempeño
MAD_train = functions.portfolio_metrics(portfolio[["timeStamp",
"Long_Entry","Exit","Position",
"Capital","Daily_Profit",
"Take_Profit","Stop_Loss","Returns",
"Cumulative_Returns"]])
MAD_test = functions.portfolio_metrics(portfolio_test[["timeStamp",
"Long_Entry","Exit","Position",
"Capital","Daily_Profit",
"Take_Profit","Stop_Loss","Returns",
"Cumulative_Returns"]])
# Visualizaciones
# Visualización de indicadores calculados sobre las series de tiempo
# Se tienen que realizar sobre el slice de la posición 1 hacia adelante porque el Aroon en 0 es 0 y hace
# que la gráfica salga espantosa
train_ind = visualizations.plot_indicators(train_df.iloc[1:,:])
test_ind = visualizations.plot_indicators(test_df.iloc[1:,:])
# Visualización de la estrategia sobre la serie de tiempo
trading_strat_train = visualizations.plot_indicators_2(portfolio.iloc[1:,:])
trading_strat_test = visualizations.plot_indicators_2(portfolio_test.iloc[1:,:])
#Visualización de la convergencia en la optimización de la estrategia
conv_graph = visualizations.plot_capital_evolution(iter_val_test)
Best take_profit_ratio: 0.01 Best stop_loss_ratio: 0.01 Best position_size: 10000.0
g_train = train_ind.show(renderer = 'notebook')
g_train
g_test = test_ind.show(renderer = 'notebook')
g_test
Cada línea verde es una entrada de la estrategia, cada línea roja, una salida de acuerdo a las reglas de salida y las reglas de take profit y stop loss
g_ttrain = trading_strat_train.show(renderer = 'notebook')
g_ttrain
gttest = trading_strat_test.show(renderer = 'notebook')
gttest
MAD_train
| Total_Return | Average_Return | Volatility | Sharpe_Ratio | |
|---|---|---|---|---|
| 0 | 2.120347 | 0.038695 | 0.787431 | -6.30062 |
MAD_test
| Total_Return | Average_Return | Volatility | Sharpe_Ratio | |
|---|---|---|---|---|
| 0 | 0.231515 | -0.027313 | 0.544409 | -9.234434 |
g_conv = conv_graph.show(renderer = 'notebook')
g_conv
Como equipo, hemos trabajado arduamente para diseñar y ejecutar cada tarea del proyecto, siguiendo la estructura básica de proyectos de Python y dividiendo las tareas predefinidas para cada perfil de manera equitativa y efectiva. La estrategia de trading fue capaz de generar un rendimiento positivo, sin embargo no fue capaz de superar a la tasa libre de riesgo establecida del 5%, dando como resultado un radio de sharpe negativo.
Para asegurarnos de que el sistema de trading propuesto sea efectivo, definimos los cuatro criterios necesarios para su éxito y realizamos una optimización y backtest financiero utilizando parámetros específicos. A través de estudios técnicos, definimos una función de utilidad y los parámetros que debían optimizarse, junto con el espacio de búsqueda y el método de optimización utilizado.
En el proceso, también consideramos los aspectos estadísticos y computacionales necesarios para garantizar la precisión de los resultados. Hemos trabajado en equipo para asegurarnos de que todos los aspectos del proyecto estén integrados y funcionando sin problemas.
Finalmente, aplicamos el sistema de trading a los datos de prueba y presentamos los resultados a través de gráficas y tablas. A través de nuestro esfuerzo conjunto y nuestro enfoque riguroso, hemos logrado desarrollar un sistema de trading sólido y eficaz, que esperamos que tenga un gran impacto en el mundo financiero.
Hemos aprendido mucho sobre análisis técnico, herramientas financieras y estrategias de trading, así como sobre la importancia de trabajar en equipo y mantener altos estándares de calidad en nuestros proyectos.